package TrainModel;

import static org.junit.Assert.*;

import org.junit.Test;

import Utilities.logFileIO;
import Utilities.TrainConstants;

public class PhysicsEngineUnitTests 
{
	// log file writer for the unit tests
	private logFileIO utLogFile;
	
	public PhysicsEngineUnitTests()
	{
		// Init log file writer
		utLogFile = new logFileIO( "PhysicsEngine_UnitTest_LogFile", "txt" );
	}

	@Test
	// Test that setting a power increases the speed
	public void powerSetting()
	{
		PhysicsEngine p = new PhysicsEngine(utLogFile, 0);
		
		p.setPower(6000);
		double vel = p.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertTrue(vel > 0);
	}
	
	@Test
	// Test that setting a power after engine failure will not increase the speed
	public void powerFailure()
	{
		PhysicsEngine p = new PhysicsEngine(utLogFile, 0);
		p.failEngine(true);
		
		p.setPower(60000);
		double vel = p.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertFalse(vel > 0);
	}
	
	@Test
	// Test that repairing an engine failure restores normal operations
	public void powerRepair()
	{
		PhysicsEngine p = new PhysicsEngine(utLogFile, 0);
		p.failEngine(true);
		p.setPower(6000);
		
		p.failEngine(false);
		p.setPower(6000);
		
		double vel = p.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertTrue(vel > 0);
	}
	
	@Test
	// Test that braking slows the train more quickly than friction alone
	public void brakesWork()
	{
		PhysicsEngine p1 = new PhysicsEngine(utLogFile, 0);
		p1.setPower(6000);
		
		PhysicsEngine p2 = new PhysicsEngine(utLogFile, 0);
		p2.setPower(6000);
		
		
		double v1 = p1.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		double v2 = p2.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		p1.setPower(0);
		p2.setBrake(100);
		
		v1 = p1.run(.5,TrainConstants.CAR_BASE_WEIGHT, 0);
		v2 = p2.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertTrue( v2 < v1);
	}
	
	@Test
	// Test that brakes don't work after a brake failure
	public void brakesFail()
	{
		PhysicsEngine p1 = new PhysicsEngine(utLogFile, 0);
		p1.setPower(6000);
		
		PhysicsEngine p2 = new PhysicsEngine(utLogFile, 0);
		p2.setPower(6000);
		
		double v1 = p1.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		double v2 = p2.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		p2.failBrakes(true);
		
		p1.setPower(0); // Do nothing
		p2.setBrake(100);
		
		v1 = p1.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		v2 = p2.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertTrue( v2 == v1);
	}
	
	@Test
	// Test that brakes work after a repair
	public void brakeRepair()
	{
		PhysicsEngine p1 = new PhysicsEngine(utLogFile, 0);
		p1.setPower(6000);
		
		PhysicsEngine p2 = new PhysicsEngine(utLogFile, 0);
		p2.setPower(6000);
		
		double v1 = p1.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		double v2 = p2.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		p2.failBrakes(true);
		p2.failBrakes(false);
		
		p1.setPower(0); // Do nothing
		p2.setBrake(100);
		
		v1 = p1.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		v2 = p2.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertTrue( v2 < v1);
	}
	
	@Test
	// Test that the wheels slippage with a power input too high
	public void wheelSlip()
	{
		PhysicsEngine p1 = new PhysicsEngine(utLogFile, 0);
		p1.setFrictionCoeffKinetic(TrainConstants.dWheelToTrackFrictionCoeffKinetic);
		p1.setFrictionCoeffStatic(TrainConstants.dWheelToTrackFrictionCoeffStatic);
		p1.setPower(60000);
		double v1 = p1.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertTrue(v1 == 0 );
	}
	
	@Test
	// Test that wheel slippage continues until a wheel stop spinning (based on coeff of kinetic friction)
	public void wheelSlipExtended()
	{
		int powerGreater = 60000;
		int powerLesser = 10000;
		// Show that 10,000 power input does not cause wheel slippage 
		PhysicsEngine p1 = new PhysicsEngine(utLogFile, 0);
		p1.setFrictionCoeffKinetic(TrainConstants.dWheelToTrackFrictionCoeffKinetic);
		p1.setFrictionCoeffStatic(TrainConstants.dWheelToTrackFrictionCoeffStatic);
		p1.setPower(powerLesser);
		double v1 = p1.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		assertFalse(v1 == 0 );
		
		// Show that 60,000 power input does cause wheel slippage
		PhysicsEngine p2 = new PhysicsEngine(utLogFile, 0);
		p2.setFrictionCoeffKinetic(TrainConstants.dWheelToTrackFrictionCoeffKinetic);
		p2.setFrictionCoeffStatic(TrainConstants.dWheelToTrackFrictionCoeffStatic);
		p2.setPower(powerGreater);
		double v2 = p2.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		assertTrue(v2 == 0 );
		
		// Show that 60,000 followed by 10,000 still has wheel slippage
		PhysicsEngine p3 = new PhysicsEngine(utLogFile, 0);
		p3.setFrictionCoeffKinetic(TrainConstants.dWheelToTrackFrictionCoeffKinetic);
		p3.setFrictionCoeffStatic(TrainConstants.dWheelToTrackFrictionCoeffStatic);
		p3.setPower(powerGreater);
		double v3 = p3.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		p3.setPower(powerLesser);
		v3 = p3.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		// Show that 60,000 followed by 10,000 still has wheel slippage
		PhysicsEngine p4 = new PhysicsEngine(utLogFile, 0);
		p4.setFrictionCoeffKinetic(TrainConstants.dWheelToTrackFrictionCoeffKinetic);
		p4.setFrictionCoeffStatic(TrainConstants.dWheelToTrackFrictionCoeffStatic);
		p4.setPower(powerGreater);
		double v4 = p4.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		p4.setPower(0); // Do nothing
		v4 = p4.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertTrue(v3 == v4 );
	}
	
	@Test
	// Test that setting an uphill grade slows the velocity
	public void gradeUp()
	{
		PhysicsEngine p1 = new PhysicsEngine(utLogFile, 0);
		p1.setPower(12000);
		double v1 = p1.run(.5, TrainConstants.CAR_BASE_WEIGHT, .2);
		
		PhysicsEngine p2 = new PhysicsEngine(utLogFile, 0);
		p2.setPower(12000);
		double v2 = p2.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertTrue(v1 < v2 );
	}
	
	@Test
	// Test that setting an uphill grade slows the velocity
	public void gradeDown()
	{
		PhysicsEngine p1 = new PhysicsEngine(utLogFile, 0);
		p1.setPower(6000);
		double v1 = p1.run(.5, TrainConstants.CAR_BASE_WEIGHT, -.1);
		
		PhysicsEngine p2 = new PhysicsEngine(utLogFile, 0);
		p2.setPower(6000);
		double v2 = p2.run(.5, TrainConstants.CAR_BASE_WEIGHT, 0);
		
		assertTrue(v1 > v2 );
	}
	
	
	

}
